﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Passwords.Utils
{
    public enum PasswordStrengthLevel
    {
        Weak,
        Medium,
        Good,
        Strong
    }
    public static class PasswordUtility
    {
        public static int GetStrength(string password)
        {
            if (password == null) throw new ArgumentNullException("password");
            int charSet = getCharSetUsed(password);
            int len =  password.Length;
            double strength = Math.Log(Math.Pow(charSet, len)) / Math.Log(2d);
            return (int)(strength + 0.5d);
        }

        public static PasswordStrengthLevel GetLevelFromValue(int strength)
        {
            if (strength < 32) return PasswordStrengthLevel.Weak;
            if (strength < 64) return PasswordStrengthLevel.Medium;
            if (strength < 128) return PasswordStrengthLevel.Good;
            return PasswordStrengthLevel.Strong;
        }



        private static int getCharSetUsed(string pass)
        {
            int ret = 0;

            if (containsNumbers(pass))
            {
                ret += 10;
            }

            if (containsLowerCaseChars(pass))
            {
                ret += 26;
            }

            if (containsUpperCaseChars(pass))
            {
                ret += 26;
            }

            if (containsPunctuation(pass))
            {
                ret += 31;
            }

            return ret;
        }

        private static bool containsNumbers(string str)
        {
            Regex pattern = new Regex(@"[\d]");
            return pattern.IsMatch(str);
        }

        private static bool containsLowerCaseChars(string str)
        {
            Regex pattern = new Regex("[a-z]");
            return pattern.IsMatch(str);
        }

        private static bool containsUpperCaseChars(string str)
        {
            Regex pattern = new Regex("[A-Z]");
            return pattern.IsMatch(str);
        }

        private static bool containsPunctuation(string str)
        {
            // regular expression include _ as a valid char for alphanumeric.. 
            // so we need to explicity state that its considered punctuation.
            Regex pattern = new Regex(@"[\W|_]");
            return pattern.IsMatch(str);
        }

        private static readonly string alnum = "01234567890abcdefghijklmnopqrstuvwxy";
        private static readonly string numeric = "01234567890";
        private static readonly string alpha = "abcdefghijklmnopqrstuvwxyz";
        private static readonly string complex = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;:!#*+-?=%$&abcdefghijklmnopqrstuvwxy";

        public static string GeneratePassword(PasswordType passwordType, int len)
        {
            string src = GetFromType(passwordType);
            StringBuilder sb = new StringBuilder();
            Random r = new Random();
            for (int i = 0; i < len; i++)
            {
                int n = r.Next(src.Length);
                sb.Append(src[n]);
            }
            return sb.ToString();
        }

        private static string GetFromType(PasswordType passwordType)
        {
            switch (passwordType)
            {
                case PasswordType.Numeric: return numeric;
                case PasswordType.Alpha: return alpha;
                case PasswordType.Alphanumeric: return alnum;
                default: return complex;
            }
        }
    }
}
